import math
from handle.base import ComparisonPosition
from yxlog.logger import get_logger

logger = get_logger(level="INFO")


class MergeParser(object):
    def __init__(self, center_id, candidate_ids, sorted_ocr_result, used_ids):
        self.candidate_ids = candidate_ids
        self._len = len(candidate_ids)
        self.usedIds = used_ids
        self._sorted_ocr_result = sorted_ocr_result
        self.center_id = center_id
        self._vertical_height_ratio = 0.8
        self._vertical_height_gap_ratio = 0.3
        self._vertical_horizontal_overlap_ratio = 0.9
        self._horizon_center_height_ratio = 0.3
        self._horizon_width_gap_ratio = 0.5
        self._min_distance_pixes = 30
        self._scope_height_gap_ratio = 1
        self._scope_width_gap_ratio = 0.5
        self.scopeIds = self._ensure_multi_line()
        self.rows = len(self.scopeIds) + 1
        self.cols = 5
        self.initForms = self.__init_merge_cells_form()
        self.print_forms()

    def __closest_to_center(self):
        distance = math.inf
        scope_id = -1
        for i in range(self._len):
            _id = self.candidate_ids[i]
            dis = abs(self._sorted_ocr_result[_id].left_point - self._sorted_ocr_result[self.center_id].left_point)
            if dis >= distance:
                continue
            cp = ComparisonPosition(self._sorted_ocr_result[_id], self._sorted_ocr_result[self.center_id])
            if cp.height_gap != 0:
                continue
            distance = dis
            scope_id = i
        if scope_id == -1:
            return []
        return [self.candidate_ids[scope_id]]

    def _ensure_multi_line(self):
        tmp_dict = dict()
        used_ids = []
        for i in range(self._len - 1):
            if i in used_ids:
                continue
            tmp_dict[self.candidate_ids[i]] = [self.candidate_ids[i]]
            used_ids.append(i)
            candidate_i = self._sorted_ocr_result[self.candidate_ids[i]]
            for j in range(i + 1, self._len):
                if j in used_ids:
                    continue
                candidate_j = self._sorted_ocr_result[self.candidate_ids[j]]
                if candidate_j.left_point >= candidate_i.right_point:
                    used_ids.append(j)
                cp = ComparisonPosition(candidate_i, candidate_j)
                left_distance_state = abs(candidate_j.left_point - candidate_i.left_point) > self._min_distance_pixes
                height_gap_state = cp.height_gap_ratio > self._scope_height_gap_ratio
                width_gap_state = cp.width_gap_ratio > self._scope_width_gap_ratio
                if left_distance_state or height_gap_state or width_gap_state:
                    continue
                used_ids.append(j)
                tmp_dict[self.candidate_ids[i]].append(self.candidate_ids[j])
                candidate_i = self._sorted_ocr_result[self.candidate_ids[j]]

        if not tmp_dict:
            scope_ids = self.__closest_to_center()
        else:
            scope_ids = sorted(tmp_dict.items(), key=lambda x: len(x[1]), reverse=True)
            scope_ids = self.__check_scope_ids(scope_ids)
            if not scope_ids or len(scope_ids) == 1:
                scope_ids = self.__closest_to_center()
        return scope_ids

    def __check_scope_ids(self, scope_ids):
        center_point = self._sorted_ocr_result[self.center_id]
        for key, vals in scope_ids:
            bottom_pos = self._sorted_ocr_result[vals[-1]].bottom_point
            if bottom_pos < center_point.bottom_point:
                continue

            min_height_gap = math.inf
            for val in vals:
                val_point = self._sorted_ocr_result[val]
                height_gap = ComparisonPosition(center_point, val_point).height_gap
                if height_gap < min_height_gap:
                    min_height_gap = height_gap
            if min_height_gap > center_point.height:
                continue
            return vals
        return []

    def print_forms(self):
        total_text = ""
        data1 = []
        for row in range(self.rows):
            data2 = []
            for col in range(self.cols):
                candidate = self.initForms[row][col]
                if candidate is None:
                    continue
                total_text += candidate.text
                data2.append(candidate.text)
            data1.append(data2)
        return total_text

    def __should_merge_vertical_line(self, cp):
        # 两行之间垂直文本高度比例
        v_cond1 = cp.height_ratio >= self._vertical_height_ratio
        # 两行之间垂直间隔与较小文本的高度比例
        v_cond2 = cp.height_gap_ratio <= self._vertical_height_gap_ratio
        # 两行文本的水平重合度
        v_cond3 = cp.horizontal_overlap_ratio > self._vertical_horizontal_overlap_ratio
        return v_cond1 and v_cond2 and v_cond3

    def __should_merge_horizontal_line(self, cp):
        # 文本行中心高度比例
        h_cond4 = cp.center_height_ratio <= self._horizon_center_height_ratio
        # 文本行中间水平间隔比例
        h_cond5 = cp.width_gap_ratio <= self._horizon_width_gap_ratio
        return h_cond4 and h_cond5

    def __merge_two_position(self, cp):
        """合并两个文本框"""
        vertical_state = self.__should_merge_vertical_line(cp)
        horizontal_state = False
        if not vertical_state:
            horizontal_state = self.__should_merge_horizontal_line(cp)

        if not vertical_state and not horizontal_state:
            logger.debug("结论：两个文本行不可以上下，左右合并\n")
            return
        logger.debug("结论：开始合并...\n")
        merge_type = "vertical" if vertical_state else "horizontal"
        return merge_type

    def __update_cells_lst(self, candidate, row):
        for col in range(self.cols):
            if self.initForms[row][col] is not None:
                continue
            self.initForms[row][col] = candidate
            break

    def __try_to_merge_text_rect(self, candidate_id):
        candidate = self._sorted_ocr_result[candidate_id]
        for _row in range(self.rows):
            for _col in range(self.cols):
                latest_item = self.initForms[_row][_col]
                if latest_item is None:
                    break

                logger.debug("待合并的两个文本框: \n\tlatest:{}\n\tcur_item:{}\n".format(latest_item.text, candidate.text))
                cp = ComparisonPosition(latest_item, candidate)
                # if latest_item.text == "【新《分类同湘" and candidate.text == "编码区】:/":
                #     import pdb
                #     pdb.set_trace()
                merge_type = self.__merge_two_position(cp)
                if not merge_type:
                    continue
                if merge_type == "vertical" and _row != len(self.scopeIds)-1:
                    continue
                self.usedIds.append(candidate_id)
                if merge_type == "vertical":
                    self.__update_cells_lst(candidate, _row+1)
                else:
                    self.__update_cells_lst(candidate, _row)
                return

    def __init_merge_cells_form(self):
        """设计为表格形式，　默认是10*5"""
        init_forms = [[None for _ in range(self.cols)] for _ in range(self.rows)]
        for row in range(len(self.scopeIds)):
            _id = self.scopeIds[row]
            init_forms[row][0] = self._sorted_ocr_result[_id]
            self.usedIds.append(_id)
        return init_forms

    def merge_rect(self):
        logger.debug("开始合并文本框")
        if not self.scopeIds:
            return ""

        for candidate_id in self.candidate_ids:
            if candidate_id in self.usedIds:
                continue
            self.__try_to_merge_text_rect(candidate_id)
        data1 = self.print_forms()
        return data1
